/*
 * Copyright (c) 2001 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 */
package net.sourceforge.perforce.ui.action;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IChangeResult;
import net.sourceforge.perforce.core.api.IChangesResult;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.core.resources.IChangelist;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.dialogs.ConfirmationDialog;
import net.sourceforge.perforce.ui.internal.Policy;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
  * @version 	$Revision: 75 $
  * @author		<a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class RevertUnchangedAction extends PerforceAction
{
	// ------------------------------------------------------------------------------ Public Methods
	
	/** @see IActionDelegate#run(IAction) */
	public void run(IAction action)
	{
		run(new WorkspaceModifyOperation()
		{
			public void execute(IProgressMonitor monitor)
				throws InvocationTargetException, InterruptedException
			{
				final IChangelist[] changelists = getSelectedChangelists();
				Policy.assertTrue(changelists.length == 1);
				
				Integer changelist = changelists[0].getId();
				try
				{
					IPerforceServer server = changelists[0].getServer();
						
					final String[] files = server.diff(getFilesOfChangelist(server, changelist));
					if (files.length == 0)
					{
						String title = 
							Policy.bind("RevertUnchangedAction.dialogTitle");          //$NON-NLS-1$
						String message =
							Policy.bind("RevertUnchangedAction.noFilesDialogMessage"); //$NON-NLS-1$
						
						MessageDialog.openInformation(getShell(), title, message);
						return;
					}
									
					final boolean[] doRevert = { false };
					getShell().getDisplay().syncExec(new Runnable() 
					{
						public void run() 
						{
							String title = 
								Policy.bind("RevertUnchangedAction.dialogTitle");      //$NON-NLS-1$
							String message =
								Policy.bind("RevertUnchangedAction.dialogMessage");    //$NON-NLS-1$
								
							doRevert[0] = ConfirmationDialog.openConfirmation(
								getShell(), title, message, files);
						}
					});	
					
					if (doRevert[0])
					{
						server.revert(files, null);
						
						IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
							
						IFile[] fileResources = new IFile[files.length];
						for (int i = 0, length = files.length; i < length; i++)
						{
							fileResources[i] = root.getFileForLocation(
								new Path(files[i]));
						}
						refreshState(fileResources, monitor);
						
						PerforceCorePlugin.getPlugin().broadcastChangelistStateChanges(changelists);
					}					
				}
				catch (PerforceException e)
				{
					throw new InvocationTargetException(e);
				}
			}
		}, PROGRESS_DIALOG);
	}
	
	// --------------------------------------------------------------------------- Protected Methods

	/** @see TeamAction#isEnabled() */
	protected boolean isEnabled() 
		throws PerforceException
	{
		IChangelist[] changelists = getSelectedChangelists();
		if (changelists.length != 1)
		{
			return false;
		}
			
		for (int i = 0; i < changelists.length; i++)
		{
			IPerforceServer server = changelists[i].getServer();
			if (!(server.getClient().equals(changelists[i].getClientName())))
			{
				return false;
			}
		}
			
		return true;
	}

	// ----------------------------------------------------------------------------- Private Methods

	/** Returns an array of files that belong to the given (pending) changelist.
	  * 
	  * @param server reference to the perforce server.
	  * @param changelist the changelist id.
	  * @return array of files
	  * 
	  * @throws PerforceException in case of an exception.
	  */
	private String[] getFilesOfChangelist(IPerforceServer server, Integer changelist) 
		throws PerforceException 
	{
		IChangeResult changeResult = server.change(changelist);
			
		Map specDataMap = changeResult.getChangeSpecData().getSpecDataMap();
		List files = new ArrayList();
		for (Iterator it = specDataMap.entrySet().iterator(); it.hasNext();)
		{
			Map.Entry entry = (Map.Entry) it.next();
			
			if (((String) entry.getKey()).startsWith("Files"))                         //$NON-NLS-1$
			{
				files.add(entry.getValue());
			}
		}
		
		return (String[]) files.toArray(new String[files.size()]);
	}

	/** Returns an array of all selected IChangesResult objects.
	  *
	  * @return array of selected...
	  */
	private IChangelist[] getSelectedChangelists()
	{
		ArrayList resources = null;
		if (!getSelection().isEmpty())
		{
			resources = new ArrayList();
			for (Iterator elements = getSelection().iterator(); elements.hasNext();)
			{
				Object next = elements.next();
				
				if (next instanceof IChangelist)
				{
					resources.add(next);
					continue;
				}
				else
				if (next instanceof IAdaptable)
				{
					IAdaptable a = (IAdaptable) next;
					Object adapter = a.getAdapter(IChangelist.class);
					if (adapter instanceof IChangesResult)
					{
						resources.add(adapter);
						continue;
					}
				}
			}
		}
		
		if (resources != null && !resources.isEmpty())
		{	
			return (IChangelist[]) resources.toArray(new IChangelist[resources.size()]);
		}
		
		return new IChangelist[0];
	}

	/** Call this method to retrieve the local state of the given files.
	  * 
	  * @param files array of files to refresh.
	  * @param monitor the progress monitor.
	  */
	private void refreshState(IFile[] files, IProgressMonitor monitor)
	{
		P4TeamProvider provider =
			(P4TeamProvider) RepositoryProvider.getProvider(
				files[0].getProject());
	
		try
		{		
			provider.refreshState(files, IResource.DEPTH_ZERO, monitor);
		}
		catch (TeamException e)
		{
			PerforceUIPlugin.log(e.getStatus());
		}
	}	
}
